package net

import (
	"fmt"
	"net"
)

type TcpClient struct {
	c          net.Conn
	remoteIp   string
	remotePort int

	dataArrival func(data []byte)
	stateChange func(state ConnectState)
}

func (u *TcpClient) Connect(ip string, port int) error {

	u.stateChangeNotify(Connecting)
	tcp, err := net.Dial("tcp", fmt.Sprintf("%v:%v", ip, port))
	if err != nil {
		u.stateChangeNotify(ConnectedError)
		return err
	}
	u.c = tcp
	u.stateChangeNotify(Connected)
	go func() {
		defer func() {
			if r := recover(); r != nil {
				u.stateChangeNotify(Disconnected)
				u.Close()
			}
		}()
		for {
			buf := make([]byte, BuffSize)
			n, err := u.c.Read(buf)
			if err != nil {
				u.stateChangeNotify(Disconnected)
				u.Close()
			} else {
				u.dataArrival(buf[:n])
			}
		}
	}()
	return nil
}

func (u *TcpClient) Send(data []byte) (int, error) {
	if u.c != nil {
		return u.c.Write(data)
	}
	return 0, fmt.Errorf("网络未连接")
}

// Close 关闭链接
func (u *TcpClient) Close() {
	if u.c != nil {
		_ = u.c.Close()
	}
	u.c = nil
	u.stateChangeNotify(Disconnected)
}

// OnDataArrival 数据到达回调函数
// func (data []byte): 数据到达回调函数
func (u *TcpClient) OnDataArrival(f func(data []byte)) {
	u.dataArrival = f
}

// OnStateChange 状态改变回调函数
func (u *TcpClient) OnStateChange(f func(state ConnectState)) {
	u.stateChange = f
}

func (u *TcpClient) stateChangeNotify(state ConnectState) {
	if u.stateChange != nil {
		go u.stateChange(state)
	}
}
